package cs301.msflags;

import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import cs301.game.GameConfig;
import cs301.game.R;

/**
 * @author John Olennikov
 * @author Kyanne Mayfield
 * @author Allie Seibert
 * @author Emilia Holbik
 * @version 12/7/2012
 * 
 *          This class contains information to launch the set up board
 *          configuration GUI intent. Furthermore, it parses and correctly
 *          records the user input for board dimensions and mines.
 */

public class MSFlagsSetupActivity extends Activity implements OnClickListener,
		TextView.OnEditorActionListener {
	
	/**
	 * Constants to describe the preset dimensions for each difficulty level
	 */
	public static final String EASY_DIM = "9";
	public static final String MED_DIM = "16";
	public static final String HARD_HEIGTH = "20";
	public static final String HARD_WIDTH = "20";
	public static final String EASY_MINES = "10";
	public static final String MED_MINES = "40";
	public static final String HARD_MINES = "99";

	/**
	 * The buttons, edit texts, and text views on configuration GUI
	 */
	private Button easyBoardButton;
	private Button mediumBoardButton;
	private Button hardBoardButton;
	private Button customBoardButton;
	private Button quitGameButton;
	private Button startGameButton;
	private Button resumeGameButton;

	private EditText widthEditText;
	private EditText heightEditText;
	private EditText numMinesEditText;

	private TextView errorNotifier;

	/**
	 * The total number of mines laid out on the game board.
	 */
	private int totalNumMines = 0;

	/**
	 * The width of the game board, i.e., the number of spaces in any row of the
	 * board.
	 */
	private int boardWidth = 0;

	/**
	 * The height of the game board, i.e., the number of spaces in any column of
	 * the board.
	 */
	private int boardHeight = 0;
	
	/**
	 * Checks if a game has already been created (not equal to null)
	 */
	private Boolean isGameCreated = false;
	
	@Override
	public final void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		Intent intent = getIntent();
		isGameCreated = intent.getBooleanExtra("isGameCreated", false);
		
		// Set the orientation to portrait
		setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
		
		// Initialize the layout
		setContentView(R.layout.game_setup);

		setupConfigListeners();

		if (!isGameCreated)
			resumeGameButton.setVisibility(View.INVISIBLE);
		else
			resumeGameButton.setVisibility(View.VISIBLE);		
	}// onCreate

	/**
	 * Keep listeners in separate function to clean up code
	 */
	public void setupConfigListeners() {
		// set up Button and EditText objects for board setup GUI
		easyBoardButton = (Button) this.findViewById(R.id.button_easy);
		mediumBoardButton = (Button) this.findViewById(R.id.button_med);
		hardBoardButton = (Button) this.findViewById(R.id.button_hard);
		customBoardButton = (Button) this.findViewById(R.id.button_custom);
		quitGameButton = (Button) this.findViewById(R.id.button_quit_game);
		startGameButton = (Button) this.findViewById(R.id.button_start_game);
		resumeGameButton = (Button) this.findViewById(R.id.button_resume_game);
			
		widthEditText = (EditText) this.findViewById(R.id.edit_text_width);
		heightEditText = (EditText) this.findViewById(R.id.edit_text_height);
		numMinesEditText = (EditText) this
				.findViewById(R.id.edit_text_num_mines);

		errorNotifier = (TextView) findViewById(R.id.error_notifier);

		// set Button listeners for board setup GUI
		easyBoardButton.setOnClickListener(this);
		mediumBoardButton.setOnClickListener(this);
		hardBoardButton.setOnClickListener(this);
		customBoardButton.setOnClickListener(this);
		startGameButton.setOnClickListener(this);
		resumeGameButton.setOnClickListener(this);

		// set EditText listeners for board setup GUI
		widthEditText.setOnEditorActionListener(this);
		heightEditText.setOnEditorActionListener(this);
		numMinesEditText.setOnEditorActionListener(this);
	}

	/**
	 * Set the text in the Board setup GUI depending on which button the
	 * user pressed.
	 */
	public void onClick(View button) {
		if (button.equals(easyBoardButton)) {
			heightEditText.setText(EASY_DIM);
			widthEditText.setText(EASY_DIM);
			numMinesEditText.setText(EASY_MINES);
		} else if (button.equals(mediumBoardButton)) {
			heightEditText.setText(MED_DIM);
			widthEditText.setText(MED_DIM);
			numMinesEditText.setText(MED_MINES);
		} else if (button.equals(hardBoardButton)
				|| button.equals(customBoardButton)) {
			heightEditText.setText(HARD_HEIGTH);
			widthEditText.setText(HARD_WIDTH);
			numMinesEditText.setText(HARD_MINES);
		} else if (button.equals(startGameButton)) {
			// gather the information from the board setup GUI
			extractInput();
		} else if (button.equals(resumeGameButton)) {
			//If the game was already created, launch a new intent containing
			//the information from the current game.
			if (isGameCreated) {
				Intent data = new Intent();
				data.putExtra("resumeGame", true);

				setResult(RESULT_OK, data);
				finish();
				
	            // Prevents animation when switching activities
	            overridePendingTransition(0,0);
			}
		} else if (button.equals(quitGameButton)) {
			//If we are quitting the game, launch a new Intent with a command
			//to then exit itself and the rest of the game.
			Intent data = new Intent();
			data.putExtra("quitGame", true);

			setResult(RESULT_OK, data);
			finish();
			
            // Prevents animation when switching activities
            overridePendingTransition(0,0);
		}
	}

	/**
	 * Gather the information from the board setup GUI
	 */
	private void extractInput() {

		// Parse board settings to strings
		try {
			boardHeight = parseInt(heightEditText.getText().toString());
			boardWidth = parseInt(widthEditText.getText().toString());
			totalNumMines = parseInt(numMinesEditText.getText().toString());
		} catch (Exception e) {
			//If the parsing is not valid, set dimensions of 0
			boardHeight = 0;
			boardWidth = 0;
			totalNumMines = 0;
		}

		boolean valid = checkValidConfiguration(boardWidth, boardHeight,
				totalNumMines);

		// If the dimensions are valid, submit settings
		if (valid) {
			Intent data = new Intent();
			data.putExtra("boardHeight", boardHeight);
			data.putExtra("boardWidth", boardWidth);
			data.putExtra("totalNumMines", totalNumMines);

			setResult(RESULT_OK, data);

			finish();
		}
	}

	/**
	 * Removes anything that is not a digit that may cause incorrectly 
	 * defined dimensions or numbers of mines.
	 * 
	 * @param input: input that has not yet been parsed
	 * @return  the correctly parsed input
	 */
	private int parseInt(String input) {
		// Remove anything that is not a digit (including periods and hyphens)
		input = input.replaceAll("[^\\d]", "");

		// Make sure the field contains a value
		if (input.length() > 0)
			return Integer.parseInt(input);
		else
			return 0;
	}

	/**
	 * Determines whether the user specified a valid width, height, and 
	 * number of mines. 
	 * 
	 * @param width: user input width of board
	 * @param height: user input height of board
	 * @param mines: user input number of mines on board
	 * @return whether or not the board configuration was valid
	 */
	private boolean checkValidConfiguration(int width, int height, int mines) {
		//If we have out of bounds widths or heights, notify the user with
		//a message.
		if (width < 9 || width > 20) {
			errorNotifier.setText("Please enter a width between 9 and 20.");
			return false;
		} else if (height < 9 || height > 20) {
			errorNotifier.setText("Please enter a height between 9 and 20.");
			return false;
		} else if (mines < 0.05 * width * height
				|| mines > 0.75 * width * height) {
			//The number of mines allowed on the board will be no less than 
			//5% of the area and no greater than 75% of the area.
			if(width * height % 20 == 0)
			{
				// if the area * 0.05 is an integer without rounding
				errorNotifier.setText("Please enter a number of mines between "
						+ ((int) (0.05 * width * height)) + " and "
						+ (int) (0.75 * width * height) + ".");
			}
			else
			{
				// else the area * 0.05 is an integer with rounding, then round
				// the number of possible mines up
				errorNotifier.setText("Please enter a number of mines between "
						+ ((int) (0.05 * width * height) + 1) + " and "
						+ (int) (0.75 * width * height) + ".");
			}
			return false;
		} else
			return true;
	}

	/**
	 * Displays the characters that the user types into the Board Configuration
	 * GUI. If the user types invalid characters, remove them.
	 * 
	 * @param view: the text view into which was typed
	 * @param actionId: the action (touch, click, type)
	 * @param event: the key press
	 * @return false so that we may continue to modify the action (so that we 
	 *         may parse the input in greater detail later)
	 */
	public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
		view.setText(view.getText().toString().replaceAll("[^\\d]", ""));
		return false;
	}

}// class MSFlagsConfigActivity
